package com.kuaimacode.kframework.api.service;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kuaimacode.kframework.api.service.weixin.WeixinApiService;
import com.kuaimacode.kframework.api.util.MaskUtil;
import com.kuaimacode.kframework.api.vo.request.*;
import com.kuaimacode.kframework.api.vo.response.CertifacateInfoResp;
import com.kuaimacode.kframework.api.vo.response.UserInfoResp;
import com.kuaimacode.kframework.api.vo.response.UserPartnerResp;
import com.kuaimacode.kframework.common.Constant;
import com.kuaimacode.kframework.component.SmsRecordService;
import com.kuaimacode.kframework.enums.WeixinRespCodeEnum;
import com.kuaimacode.kframework.exception.ErrorEnum;
import com.kuaimacode.kframework.exception.ServerInternalErrorException;
import com.kuaimacode.kframework.mybatis.mapper.user.UserMapper;
import com.kuaimacode.kframework.mybatis.models.user.User;
import com.kuaimacode.kframework.mybatis.models.user.UserCertifacate;
import com.kuaimacode.kframework.mybatis.models.user.UserRole;
import com.kuaimacode.kframework.weixin.WXCore;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.omg.CORBA.ServiceInformation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import weixin.popular.bean.sns.Jscode2sessionResult;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
public class UserService extends ServiceImpl<UserMapper,User> {

    @Autowired
    private UserCertifacateService certifacateService;
    @Autowired
    private UserCouponService userCouponService;
    @Autowired
    private SmsRecordService smsRecordService;
    @Autowired
    private AgentService agentService;
    @Autowired
    private WeixinApiService weixinApiService;
    @Value("${weixin.applets.appId}")
    private String weixinAppId;

    public User selectByName(String username) {
        
        QueryWrapper<User> qryWrapper = new QueryWrapper<>();
        qryWrapper.eq("username", username);
        
        return baseMapper.selectOne(qryWrapper);
    }

    public User selectByPhone(String phone) {
        
        QueryWrapper<User> qryWrapper = new QueryWrapper<>();
        qryWrapper.eq("phone", phone);
        return baseMapper.selectOne(qryWrapper);
    }

    public User selectByEmail(String email) {
        
        QueryWrapper<User> qryWrapper = new QueryWrapper<>();
        qryWrapper.eq("email", email);
        return baseMapper.selectOne(qryWrapper);
    }

    public User selectByOpenId(String openId) {
        
        QueryWrapper<User> qryWrapper = new QueryWrapper<>();
        qryWrapper.eq("open_id", openId);
        return baseMapper.selectOne(qryWrapper);
    }

    public User selectByUnionId(String unionId) {
        QueryWrapper<User> qryWrapper = new QueryWrapper<>();
        qryWrapper.eq("union_id", unionId);
        return baseMapper.selectOne(qryWrapper);
    }

    public void deleteByUniondId(String unionId, String openId) {
        QueryWrapper<User> qryWrapper = new QueryWrapper<>();
        qryWrapper.eq("union_id", unionId);
        qryWrapper.eq("open_id", openId);
        baseMapper.delete(qryWrapper);
    }

    /**
     * 绑定手机号
     * @param mobile
     * @param verifyCode
     */
    public void bindMobile(String mobile, String verifyCode, Long userId) {
        User user = this.selectByPhone(mobile);
        if (user != null) {
            throw new ServerInternalErrorException(ErrorEnum.PHONE_ALREADY_EXISTS);
        }
        if (!smsRecordService.validVerifyCode(mobile, verifyCode)) {
            throw new ServerInternalErrorException(ErrorEnum.VERIFY_CODE_IS_EXPIRED);
        }
        User update = new User();
        update.setId(userId);
        update.setUsername(mobile);
        update.setNickname("用户" + MaskUtil.interceptBack4(mobile));
        update.setPhone(mobile);
        baseMapper.updateById(update);
    }
    
    
    public List<UserRole> getRoles(Long userId) {
        return baseMapper.getRoles(userId);
    }
    

    @Transactional
    public boolean add(User user) {
        //user.setPassword(crypt);
        return baseMapper.insert(user) > 0;
    }

    @Transactional
    public boolean modifyById(User user) {
        //User original = baseMapper.getById(user);
        return baseMapper.updateById(user) > 0;
    }

    /**
     * 修改个人信息
     * @param infoReq
     * @return
     */
    public boolean updatePersonInfo(UpdatePersonInfoReq infoReq) {
        User updateUser = new User();
        BeanUtils.copyProperties(infoReq, updateUser);
        return baseMapper.updateById(updateUser) > 0;
    }

    /**
     * 校验验证码
     * @param infoReq
     * @return
     */
    public void checkValidCode(CheckValidCodeReq validCodeReq) {
        User user = this.selectByPhone(validCodeReq.getPhone());
        if (user == null) {
            throw new ServerInternalErrorException(ErrorEnum.USER_NOT_EXISTS);
        }
        if (!validCodeReq.getVerifyCode().equals(user.getSmsCode()) || (new Date().after(user.getSmsTime()))) {
            throw new ServerInternalErrorException(ErrorEnum.VERIFY_CODE_VALID_ERROR);
        }
    }

    /**
     * 修改手机号
     * @param req
     */
    public void updatePhone(UpdatePhoneReq req) {
        if (req.getNewPhone().equals(req.getOldPhone())) {
            throw new ServerInternalErrorException(ErrorEnum.NEW_PHONE_EQUALS_OLD_PHONE);
        }
        //查询用户信息
        User user = baseMapper.selectById(req.getId());
        if (user == null || !user.getPhone().equals(req.getOldPhone())) {
            throw new ServerInternalErrorException(ErrorEnum.OLD_PHONE_ERROR);
        }
        //校验验证码是否正确
        if (!smsRecordService.validVerifyCode(req.getNewPhone(), req.getVerifyCode())) {
            throw new ServerInternalErrorException(ErrorEnum.VERIFY_CODE_VALID_ERROR);
        }
        //校验新手机号是否存在
        if (this.selectByPhone(req.getNewPhone()) != null) {
            throw new ServerInternalErrorException(ErrorEnum.PHONE_ALREADY_EXISTS);
        }
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setPhone(req.getNewPhone());
        updateUser.setUsername(req.getNewPhone());
        if (baseMapper.updateById(updateUser) < 1) {
            throw new ServerInternalErrorException(ErrorEnum.SYSTEM_ERROR);
        }
    }

    /**
     * 查询用户实名信息
     * @param userId
     * @return
     */
    public CertifacateInfoResp certifacateInfo(Long userId) {
        CertifacateInfoResp infoResp = CertifacateInfoResp.defaultInstance();

        UserCertifacate certifacate = certifacateService.selectByUserId(userId);
        if (certifacate == null) {
            return infoResp;
        }
        BeanUtils.copyProperties(certifacate, infoResp);
        if (!StringUtils.isAnyBlank(certifacate.getCardNegative(), certifacate.getCardPositive())) {
            infoResp.setCardImg(1);
        }
        if (StringUtils.isNotBlank(certifacate.getHeadPic())) {
            infoResp.setHeadImg(1);
        }
        return infoResp;
    }

    /**
     * 用户同意协议
     * @param userId
     */
    public void agreeProtocol(Long userId) {
        User user = new User();
        user.setIsProtocol((short) 1);
        user.setId(userId);
        baseMapper.updateById(user);
    }

    /**
     * 我的与个人信息页面获取用户信息
     * @param userId
     * @return
     */
    public UserInfoResp getUserInfo(Long userId) {
        User user = baseMapper.selectById(userId);
        UserInfoResp infoResp = new UserInfoResp();
        BeanUtils.copyProperties(user, infoResp);
        infoResp.setAccountBalance(Optional.ofNullable(user.getAccountBalance())
                .map(balance -> balance.setScale(2).toString())
                .orElse("0")
        );
        Optional.ofNullable(infoResp.getCollectBal()).ifPresent(balance -> infoResp.setCollectBal(balance.setScale(2)));
        infoResp.setCoupon(
                Optional.ofNullable(userCouponService.queryStatusCount(userId, Constant.COUPON_STATUS_NOT_USED))
                        .orElse(0)
        );
        //查询实名信息
        if (user.isCertificated()) {
            UserCertifacate certifacate = certifacateService.selectByUserId(user.getId());
            infoResp.setRealName(certifacate.getName());
            infoResp.setIdCard(MaskUtil.maskIdCard(certifacate.getIdCard()));
        }
        return infoResp;
    }

    /**
     * 获取是否合作商家
     * @param userId
     * @return
     */
    public UserPartnerResp getPartner(Long userId) {
        User user = baseMapper.selectById(userId);
        UserPartnerResp infoResp = new UserPartnerResp();
        BeanUtils.copyProperties(user, infoResp);
        infoResp.setIsPartner(Optional.ofNullable(infoResp.getIsPartner()).orElse(Constant.IsOrNotEnum.NOT.getCode()));
        return infoResp;
    }

    /**
     * 申请为合作商家
     * @param applyPartnerReq
     * @param userId
     */
    public boolean applyPartner(ApplyPartnerReq applyPartnerReq, Long userId) {
        User user = baseMapper.selectById(userId);
        if (user == null) {
            throw new ServerInternalErrorException(ErrorEnum.USER_NOT_EXISTS);
        }
        if (user.isAgreePartner()) {
            throw new ServerInternalErrorException(ErrorEnum.USER_ALREADY_IS_PARTNER);
        }
        //校验所在分站是否开通
        if (Constant.DEFAULT_AGENT_ID.equals(applyPartnerReq.getPartnerAreaCode()) || !agentService.isOpened(applyPartnerReq.getPartnerAreaCode())) {
            throw new ServerInternalErrorException(ErrorEnum.AGENT_NOT_OPEN);
        }

        User updateUser = new User();
        BeanUtils.copyProperties(applyPartnerReq, updateUser);
        updateUser.setPartnerStatus(user.getPartnerStatus());
        updateUser.setId(user.getId());
        updateUser.applyPartner(applyPartnerReq.getPartnerAreaCode());
        return baseMapper.updateById(updateUser) == 1;
    }

    public void updateUserToken(Long userId, String token) {
        User user = new User();
        user.setId(userId);
        user.setToken(token);
        baseMapper.updateById(user);
    }

    public User appletsLoginNew(AppletsLoginNewReq loginReq) {
        String phone;
        String openId = "", unionId = "";
        //自定义手机号登录
        if (loginReq.getEncrypt() == 0) {
            phone = loginReq.getPhone();
            String validCode = Optional.ofNullable(loginReq.getValidCode()).orElseThrow(() -> new ServerInternalErrorException(ErrorEnum.PARAM_VALID_ERROR));
            if (!smsRecordService.validVerifyCode(phone, validCode)) {
                throw new ServerInternalErrorException(ErrorEnum.VERIFY_CODE_VALID_ERROR);
            }
        } else {
            //查询session_key
            Jscode2sessionResult result = weixinApiService.getMsgByAppletsLoginCode(loginReq.getCode());
            if (StringUtils.isBlank(result.getSession_key())) {
                throw new ServerInternalErrorException(result.getErrcode(), result.getErrmsg());
            }
            //解密手机号
            String decryptStr = WXCore.decrypt(weixinAppId, loginReq.getPhone(), result.getSession_key(), loginReq.getIv());
            log.info("decryptStr: {}, data: {}, sessionKey: {}, iv: {}", decryptStr, loginReq.getPhone(), result.getSession_key(), loginReq.getIv());
            JSONObject jsonObject = JSONObject.parseObject(decryptStr);
            phone = Optional.ofNullable(jsonObject)
                    .map(object -> object.getString("phoneNumber"))
                    .filter(StringUtils::isNotBlank)
                    .orElseThrow(() -> new ServerInternalErrorException(ErrorEnum.DECRYPT_MOBILE_ERROR));
            openId = Optional.ofNullable(result.getOpenid()).orElse("");
            unionId = Optional.ofNullable(result.getUnionid()).orElse("");
        }
        //如果openID已被绑定，则优先解绑
        User resultUser = selectByPhone(phone);
        if (resultUser == null) {
            resultUser = new User();
            resultUser.setUsername(phone);
            resultUser.setPhone(phone);
            resultUser.setUnionId(unionId);
            resultUser.setOpenId(openId);
            resultUser.setEnabled(1);
            add(resultUser);
        } else if (StringUtils.isBlank(resultUser.getUnionId())) {
            resultUser.setOpenId(openId);
            resultUser.setUnionId(unionId);
            updateById(resultUser);
        }
        return resultUser;
    }

    public void updateAppletsFormId(String formIds, Long userId) {

        List<String> formIdList = Arrays.stream(formIds.split(",")).collect(Collectors.toList());
        User user = getById(userId);
        if (StringUtils.isNotBlank(user.getFormId())) {
            formIdList.addAll(0, Arrays.asList(user.getFormId().split(",")));
        }
        formIdList = formIdList.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());

        int size = formIdList.size();
        int fromIndex = size > 30 ? size - 30 : 0;
        formIdList = formIdList.subList(fromIndex, size);
        StringBuilder stringBuilder = new StringBuilder();
        formIdList.forEach(formId -> {
            stringBuilder.append(formId);
            stringBuilder.append(",");
        });
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setFormId(stringBuilder.length() == 0 ? "" : stringBuilder.substring(0, stringBuilder.length() - 1));
        updateById(updateUser);
    }

    /**
     * 修改用户最后登录信息
     * @param userId
     * @param ip
     */
    public void updateLastLoginInfo(Long userId, String ip) {
        User user = new User();
        user.setId(userId);
        user.setLastLoginIp(ip);
        user.setLastLoginDate(new Date());
        baseMapper.updateById(user);
    }
}